React学习笔记(二)—— 理解JSX


JSX(JavaScriptXML)提供了一种在JavaScript中编写声明式的XML的方法,使用JSX可以提高组件的可读性,React允许做简单的JSX语法转化。

简介

JSX像是在JavaScript代码里直接写XML的语法,每一个XML标签都会被JSX转换工具转换成纯JavaScript代码,React 官方推荐使用JSX,这个看个人习惯, 如果你喜欢纯JavaScript代码也是可以的,只是使用JSX会给我们带来如下好处:

  • 是原生的JavaScript;
  • 程序结构更容易被直观化;
  • 提供更加语义化且易懂的标签;
  • 抽象了React Element的创建过程;
  • 允许使用熟悉的语法来定义HTML元素树;
  • 可以随时掌控HTML标签以及生成这些标签的代码;

定义第一个组件

简单的理解组件就是对数据和方法的简单封装,目的就是模块化功能。在React当中组件是用来分离关注点的,而不是被当做模板或处理显示逻辑的,在使用React开发应用过程中,往往HTML标签以及生成这些标签的代码之间存在着内在的紧密联系,其实这一坨代码就可以理解为是一个组件。

接下来看一个简单的DEMO,定义我们的第一个组件,按照以往的游戏规则,我们就给他起一个文雅又响亮的名字——“HelloWorld”(React的安装包可以到官网去下载):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html>
<head>
<title>Hello React</title>
<!--React核心库-->
<script src="build/react.js"></script>
<!--react-dom.js提供与DOM相关功能-->
<script src="build/react-dom.js"></script>
<!--browser.js将 JSX 语法转为 JavaScript 语法-->
<script src="build/browser.min.js">/script>
</head>
<body>
<HelloWorld>Hello World!</HelloWorld>
<!--为了把 JSX 转成标准的 JavaScript,我们用 `<script type="text/babel">` 标签,然后通过Babel转换成在浏览器中真正执行的内容-->
<script type="text/babel">
// 定义组件HelloWorld
var HelloWorld = React.createClass({
render : function(){
return (
<div>
<h1>this.props.children</h1>
</div>
);
}
})
</script>
</body>
</html>

关于上例中的几点说明

  • React中组件名必须以大写字母开头;
  • React中的组件只能包含一个顶层标签,否则会报错;
  • JSX将两个花括号之间的内容{...}渲染为动态值,花括号指明了一个JavaScript上下文环境,它会将其中内容进行求值,然后渲染为标签中的若干节点;
  • this.props.children是组件的特殊属性,保存了开始标签与结束标签之间的所有子节点,上例中this.props.children = [“Hello World!”];

上述代码如果不使用JSX语法,写法如下:

1
2
3
4
5
6
7
8
9
10
11
...
// 定义组件HelloWorld
var HelloWorld = React.createClass({displayName:"HelloWorld ",
render : function(){
return (
React.createElement("div",null);
React.createElement("h2",null,this.props.children);
);
}
})
...

不管使不使用JSX,HelloWorld组件最终的页面渲染结果都是一样的,如下所示:

1
2
3
<div>
<h1>Hello World!</h1>
</div>

JSX与HTML有何不同

“这个规范(JSX)并不尝试去遵循任何XML或HTML规范。JSX是作为一种ECMAScript特性来设计的,至于大家觉得JSX像XML这一事实,那仅仅是因为大家比较熟悉XML。”——以上内容摘自http://facebook.github.io/jsx/

由此我们可以看出JSX仅仅是像HTML而已,接下来看下他们之间的关键区别。

属性

在HTML中我们往往通过内联的方式设置标签的属性,JSX在支持这种方式的基础上,还支持动态的设置标签的属性,具体实现形式如同我们上个DEMO中的{...},我们可以将属性值定义为JS变量或者是函数。如下所示:

1
2
3
4
5
6
7
8
9
10
<!--在HTML中标签属性示例-->
<div id="demo" class="myStyle"></div>

<!--在JSX中标签属性示例-->
var demoId = this.props.id;
var demoClass = "myStyle";
function getName(){
...
}
<div id={demoId} name={this.getName()} className={demoClass}></div>

在React渲染组件的过程中,我们上面定义的变量和函数会被求值,最终生成的DOM结构会反映出这个新的状态。

非DOM属性

下列属性只在JSX中存在:

  • key:可选的唯一标示符,用来唯一的标识一个组件;
  • ref :允许父组件在render之外保持对子组件的一个引用;
  • dangerouslySetInnerHtml:提供插入纯 HTML 字符串的功能,主要为了能和生成 DOM 字符串的库整合;

接下来详细看一下这几个特殊属性的作用。

键(key)
在程序运行过程中,由于用户与应用间的交互等原因,一个组件在组件树中的位置很有可能发生改变,最常见的例子就是某列表记录的增、删操作。当然这种情形下组件可能并不需要被销毁并重新创建。

通过给组件设置一个唯一的标识,且保证它在一个渲染周期中保持一致,这样React就能智能的决定该重用哪一个组件,或者销毁并重新创建一个组件,避免不必要的重新渲染,得到性能的提升。

引用(ref)
在JSX中可以通过在属性中设置期望的引用名来定义一个引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var App = React.createClass({ 
getInitialState: function() {
return {userInput: ''};
},
handleChange: function(e) {
this.setState({userInput: e.target.value});
},
clearAndFocusInput: function() {
// 清空输入框
this.setState({userInput: ''},
function() {
// 这段代码会在组件重新渲染后执行,使输入框重获焦点
this.refs.theInput.getDOMNode().focus();
});
},
render: function() {
return (
<div>
<div onClick={this.clearAndFocusInput}>
点我!点我!!点我!!!
</div>
<input ref="theInput" value={this.state.userInput} onChange={this.handleChange} />
</div>
);
}
});

然后我们就可以在组件中的任何地方使用这个引用了。通过引用获取到的这个对象叫做支持实例。他并不是一个真的DOM,而是React在需要时创建的一个描述对象。你可以通过this.refs.theInput.getDomNode()来访问真实的DOM节点。

设置原始的HTML
dangerouslySetInnerHTML—— 顾名思义,从属性名当中就能看出来,以此来警告它的值( 一个对象而不是字符串 )应该被用来表明净化后的数据。在彻底的理解安全问题后果并正确地净化数据之后,生成只包含唯一 key __html 的对象,并且对象的值是净化后的数据,示例如下:

1
2
3
4
function createMarkup() { 
return {__html: 'First · Second'};
};
<div dangerouslySetInnerHTML={createMarkup()} />

这么做的意义在于,当你不是有意地使用 <div dangerouslySetInnerHTML={getUsername()} />时候,它并不会被渲染,因为 getUsername() 返回的格式是字符串而不是一个{__html: ''} 对象。{__html:''} 背后的目的是表明它会被当成 type/taint 类型处理。这种包裹对象,可以通过方法调用返回净化后的数据,随后这种标记过的数据可以被传递给dangerouslySetInnerHTML

这个功能主要被用来与DOM字符串操作类库一起使用,所以提供的HTML必须要格式清晰(例如:传递XML校验 )

注释

由于JSX本质上就是JavaScript,因此也支持JavaScript的注释方式,在JSX中可以用以下两种方式添加注释:

  • 当做一个元素的子节点;
  • 内联在元素的属性中;

示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 作为一个元素的子节点
<div>
{/*多行注释*/}
<h1>This is a h1 tag.</h1>
</div>

// 内联在元素的属性中
<div>
<h1
/*
* 多行注释
*/
> 多行注释 </h1>
</div>

<div>
<h1
//单行注释
>单行注释</h1>
</div>

特殊属性

由于JSX会转化为JavaScript函数,所以有些关键词我们不可以使用,比如forclass

这两个属性分别可以用htmlForclassName替换,参考如下示例:

1
2
<label htmlFor="name" ...>
<input calssName={classes} ...>

样式

React把所有的内联样式都规范化为驼峰形式,同样类似于JavaScript中DOM的style属性,要给组件添加自定义属性,如下:

1
2
3
4
5
6
var styles = {
width:100px;
height:100px;
}

React.renderComponent({<div style={styles}>...</div>,node})

参考

【1】《React引领未来的用户界面开发框架》
【2】 React中文官网

文章目录
  1. 1. 简介
  2. 2. 定义第一个组件
  3. 3. JSX与HTML有何不同
    1. 3.1. 属性
    2. 3.2. 非DOM属性
    3. 3.3. 注释
    4. 3.4. 特殊属性
    5. 3.5. 样式
  4. 4. 参考
,